package fr.obsmip.sedoo.server.service.dtotool;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.sis.metadata.iso.distribution.DefaultFormat;
import org.apache.sis.util.iso.DefaultInternationalString;
import org.opengis.metadata.distribution.Format;
import org.opengis.metadata.maintenance.ScopeCode;

import fr.obsmip.sedoo.shared.domain.DatasetDTO;
import fr.obsmip.sedoo.shared.domain.ExperimentalSiteDTO;
import fr.obsmip.sedoo.shared.domain.SummaryDTO;
import fr.sedoo.commons.client.util.StringUtil;
import fr.sedoo.commons.metadata.shared.ResourceIdentifier;
import fr.sedoo.commons.metadata.shared.ResourceLink;
import fr.sedoo.commons.metadata.shared.constant.Iso19139Constants;
import fr.sedoo.commons.metadata.shared.utils.Iso6392LanguageConverter;
import fr.sedoo.commons.metadata.utils.domain.MetadataTools;
import fr.sedoo.commons.metadata.utils.domain.SedooMetadata;
import fr.sedoo.commons.metadata.utils.domain.Summary;
import fr.sedoo.metadata.shared.domain.MetadataDTO;
import fr.sedoo.metadata.shared.domain.MetadataSummaryDTO;
import fr.sedoo.metadata.shared.domain.dto.FormatDTO;
import fr.sedoo.metadata.shared.domain.dto.I18nString;
import fr.sedoo.metadata.shared.domain.dto.IdentifiedResourceIdentifier;
import fr.sedoo.metadata.shared.domain.dto.InternetLink;
import fr.sedoo.metadata.shared.domain.part.ConstraintPart;
import fr.sedoo.metadata.shared.domain.part.ContactPart;
import fr.sedoo.metadata.shared.domain.part.GeographicalLocationPart;
import fr.sedoo.metadata.shared.domain.part.IdentificationPart;
import fr.sedoo.metadata.shared.domain.part.KeywordPart;
import fr.sedoo.metadata.shared.domain.part.OtherPart;
import fr.sedoo.metadata.shared.domain.part.TemporalExtentPart;

public class MetadataDTOTools extends MetadataTools
{
	
	protected MetadataDTOTools()
	{
		super();
	}

	public static SedooMetadata toMetadata(MetadataDTO metadataDTO, List<String> displayLanguages) throws Exception
	{
		SedooMetadata metadata = new SedooMetadata();
		//We set the metadataLanguage first to be able to set default display value for i18n string
		metadata.setMetadataLanguage(metadataDTO.getOtherPart().getMetadataLanguage());
		String metadataLanguage =  metadataDTO.getOtherPart().getMetadataLanguage();

		// Identification Part

		IdentificationPart identificationPart = metadataDTO.getIdentificationPart();

		metadata.setResourceTitle(toLocaleMap(identificationPart.getResourceTitle().getI18nValues()), getDefaultValue(identificationPart.getResourceTitle().getI18nValues(), metadataLanguage));
		metadata.setResourceAbstract(toLocaleMap(identificationPart.getResourceAbstract().getI18nValues()), getDefaultValue(identificationPart.getResourceTitle().getI18nValues(), metadataLanguage));
		
//		metadata.setResourceAlternateTitle(identificationPart.getResourceAlternateTitle());
		metadata.setResourceURL(identificationPart.getResourceURL());
		metadata.setSnapshotURL(DescribedURLTools.toDescribedURLList(identificationPart.getSnapshots()));
		metadata.setStatus(StringUtils.trimToEmpty(identificationPart.getResourceStatus()));
		metadata.setResourceIdentifiers(identificationPart.getResourceIdentifiers());
		if (StringUtil.trimToEmpty(identificationPart.getHierarchyLevel()).compareToIgnoreCase(Iso19139Constants.SERIES)==0)
		{
			metadata.setHierarchyLevels(Collections.singletonList(ScopeCode.SERIES));
			metadata.setHierarchyLevelNames(Collections.singletonList(identificationPart.getHierarchyLevelName()));
		}
		else
		{
			metadata.setHierarchyLevels(Collections.singletonList(ScopeCode.DATASET));
		}
		
		//Keyword part
		
		KeywordPart keywordPart = metadataDTO.getKeywordPart();
		metadata.setKeywords(keywordPart.getKeywords());

		// Geographical Part
		GeographicalLocationPart geographicalLocationPart = metadataDTO.getGeographicalLocationPart();
		metadata.setGeographicBoundingBoxes(GeographicBoundingBoxDTOTools.fromDTOList(geographicalLocationPart.getBoxes()));

		// Temporal Part
		TemporalExtentPart temporalExtentPart = metadataDTO.getTemporalExtentPart();

		metadata.setResourceBeginDate(temporalExtentPart.getStartDate());
		metadata.setResourceEndDate(temporalExtentPart.getEndDate());
		metadata.setCreationDate(temporalExtentPart.getCreationDate());
		metadata.setPublicationDate(temporalExtentPart.getPublicationDate());
		metadata.setLastRevisionDate(temporalExtentPart.getLastRevisionDate());
		metadata.setResourceUpdateRythm(temporalExtentPart.getUpdateRythm());

		// Constraint Part
		ConstraintPart constraintPart = metadataDTO.getConstraintPart();

		metadata.setPublicAccessLimitations(toLocaleMap(constraintPart.getPublicAccessLimitations().getI18nValues()), getDefaultValue(constraintPart.getPublicAccessLimitations().getI18nValues(), metadataLanguage));
		metadata.setUseConditions(toLocaleMap(constraintPart.getUseConditions().getI18nValues()), getDefaultValue(constraintPart.getUseConditions().getI18nValues(), metadataLanguage));
		
		//Contact Part
		ContactPart contactPart = metadataDTO.getContactPart();
		metadata.setMetadataContacts(MetadataContactDTOTools.toContactList(contactPart.getMetadataContacts()));
		metadata.setResourceContacts(MetadataContactDTOTools.toContactList(contactPart.getResourceContacts()));
		
		// Other Part
		OtherPart otherPart = metadataDTO.getOtherPart();

		metadata.setUuid(StringUtils.trimToEmpty(otherPart.getUuid()));
		metadata.setMetadataDate(StringUtils.trimToEmpty(otherPart.getMetadataLastModificationDate()));
		metadata.setResourceEncodingCharset(otherPart.getCharset());
		metadata.setResourceLanguages(otherPart.getResourceLanguages());
		
		if (!(StringUtils.isEmpty(otherPart.getCoordinateSystem())))
		{
			metadata.setCoordinateSystem(otherPart.getCoordinateSystem());
		}
		if (otherPart.getFormat() != null)
		{
			DefaultFormat format = new DefaultFormat();
			format.setName(new DefaultInternationalString(otherPart.getFormat().getName()));
			if (otherPart.getFormat().getStringVersions() != null)
			{
				format.setVersion(new DefaultInternationalString(otherPart.getFormat().getStringVersions()));
			}
			metadata.setResourceFormat(format);
		}
		
		
		 if (metadataDTO instanceof ExperimentalSiteDTO)
		 {
			 ExperimentalSiteDTO aux = (ExperimentalSiteDTO) metadataDTO;
			 metadata.setParentIdentifier(aux.getParentSummary().getUuid());
		 }
		 
		 if (metadataDTO instanceof DatasetDTO)
		 {
			 DatasetDTO aux = (DatasetDTO) metadataDTO;
			 metadata.setParentIdentifier(aux.getExperimentalSiteSummary().getUuid());
			 metadata.setResourceGenealogy(toLocaleMap(aux.getMeasurementPart().getResourceGenealogy().getI18nValues()), getDefaultValue(aux.getMeasurementPart().getResourceGenealogy().getI18nValues(), metadataLanguage));
		 }
		 
		return metadata;
	}

	public static List<SummaryDTO> toSummaryDTO(List<Summary> summaries, ArrayList<String> languages)
	{
		List<SummaryDTO> summaryDTOs = new ArrayList<SummaryDTO>();
		Long id = 0L;
		for (Iterator<Summary> iterator = summaries.iterator(); iterator.hasNext();)
		{
			Summary summary = iterator.next();
			SummaryDTO summaryDTO = toSummaryDTO(summary, languages);
			summaryDTO.setId(id);
			id++;
			summaryDTOs.add(summaryDTO);
		}

		return summaryDTOs;
	}

	public static SummaryDTO toSummaryDTO(Summary summary, ArrayList<String> languages)
	{
		SummaryDTO summaryDTO = new SummaryDTO();
		if (summary != null)
		{
			//We add default value as translations
			if (summary.getMetadataLanguage() != null)
			{
				summary.addTitleTranslation(summary.getMetadataLanguage(),summary.getResourceTitle());
				summary.addAbstractTranslation(summary.getMetadataLanguage(),summary.getResourceAbstract());
			}
			summary.setResourceTitle(getValue(summary.getTitleTranslations(), summary.getResourceTitle(), languages));
			summary.setResourceAbstract(getValue(summary.getAbstractTrasnlations(), summary.getResourceAbstract(), languages));
			
			summaryDTO.setResourceAbstract(summary.getResourceAbstract());
			summaryDTO.setResourceTitle(summary.getResourceTitle());
			summaryDTO.setUuid(summary.getUuid());
			summaryDTO.setModificationDate(summary.getModificationDate());
			summaryDTO.setLinks(DescribedURLTools.fromDescribedURLList(summary.getLinks()));
			summaryDTO.setHierarchyLevelName(summary.getHierarchyLevelName());
		}
		return summaryDTO;
	}
	
	public static String getValue(HashMap<String, String> translations, String defaultValue, ArrayList<String> languages)
	{
		for (String language : languages) {
			String aux = translations.get(language.toLowerCase());
			if (StringUtils.isEmpty(aux)== false)
			{
				return aux.trim();
			}
		}
		return StringUtils.trimToEmpty(defaultValue);
	}

	public static MetadataDTO toMetadatoDTO(SedooMetadata metadata, List<String> alternateLanguages)
	{
		return toMetadatoDTO(metadata, new MetadataDTO(), alternateLanguages);
	}
	public static MetadataDTO toMetadatoDTO(SedooMetadata metadata, MetadataDTO dto, List<String> alternateLanguages)
	{
		

		// Identification part
		IdentificationPart identificationPart = dto.getIdentificationPart();

		String metadataLanguage = metadata.getMetadataLanguage();
		if (StringUtils.isEmpty(metadataLanguage))
		{
			metadataLanguage = Iso6392LanguageConverter.ENGLISH;
		}
		
		Locale metadataLocale = new Locale(Iso6392LanguageConverter.convertIso6392Tolocale(metadataLanguage));
		List<Locale> alternateLocales = new ArrayList<Locale>();
		for (String language : alternateLanguages) {
			alternateLocales.add(new Locale(Iso6392LanguageConverter.convertIso6392Tolocale(language)));
		}
		
		identificationPart.setResourceTitle(toI18nString(metadata.getResourceTitle(metadataLocale, alternateLocales)));
		identificationPart.setResourceAbstract(toI18nString(metadata.getResourceAbstract(metadataLocale, alternateLocales)));
		
		identificationPart.setResourceStatus(metadata.getStatus());
		identificationPart.setResourceURL(toInternetLinks(metadata.getResourceURL()));
		identificationPart.setSnapshots(DescribedURLTools.fromDescribedURLList(metadata.getSnapshotURL()));
		
		identificationPart.setResourceIdentifiers(toIdentifierResourceIdentifiers(metadata.getResourceIdentifiers()));
		
		if ((metadata.getHierarchyLevels() != null) && ((metadata.getHierarchyLevels().size()>0)))
		{
			ScopeCode hierachyLevel = metadata.getHierarchyLevels().iterator().next();
			if (hierachyLevel.identifier().compareToIgnoreCase(Iso19139Constants.SERIES)==0)
			{
				identificationPart.setHierarchyLevel(Iso19139Constants.SERIES);
			}
			else
			{
				identificationPart.setHierarchyLevel(Iso19139Constants.DATASET);
			}
		}
		else
		{
			identificationPart.setHierarchyLevel(Iso19139Constants.DATASET);
		}
		

		if ((metadata.getHierarchyLevelNames() != null) && ((metadata.getHierarchyLevelNames().size()>0)))
		{
			identificationPart.setHierarchyLevelName(metadata.getHierarchyLevelNames().iterator().next());
		}
		
		//Contact part
		ContactPart contactPart = dto.getContactPart();
		contactPart.setMetadataContacts(MetadataContactDTOTools.fromContactList(metadata.getMetadataContacts()));
		contactPart.setResourceContacts(MetadataContactDTOTools.fromContactList(metadata.getResourceContacts()));
		
		//Keyword part
		
		KeywordPart keywordPart = dto.getKeywordPart();
		keywordPart.setKeywords(metadata.getKeywords());
		
		// Temporal Part
		TemporalExtentPart temporalExtentPart = dto.getTemporalExtentPart();

		temporalExtentPart.setEndDate(metadata.getResourceEndDate());
		temporalExtentPart.setStartDate(metadata.getResourceBeginDate());
		temporalExtentPart.setCreationDate(metadata.getCreationDate());
		temporalExtentPart.setPublicationDate(metadata.getPublicationDate());
		temporalExtentPart.setLastRevisionDate(metadata.getLastRevisionDate());
		temporalExtentPart.setUpdateRythm(metadata.getResourceUpdateRythm());

		// Geographical Part

		GeographicalLocationPart geographicalLocationPart = dto.getGeographicalLocationPart();
		geographicalLocationPart.setBoxes(GeographicBoundingBoxDTOTools.toDTOList(metadata.getGeographicBoundingBoxes()));

		// Constraint Part
		ConstraintPart constraintPart = dto.getConstraintPart();
		
		constraintPart.setPublicAccessLimitations(toI18nString(metadata.getPublicAccessLimitations(metadataLocale, alternateLocales)));
		constraintPart.setUseConditions(toI18nString(metadata.getUseConditions(metadataLocale, alternateLocales)));

//		constraintPart.setPublicAccessLimitations(metadata.getPublicAccessLimitations());
//		constraintPart.setUseConditions(metadata.getUseConditions());

		
		// Other Part
		OtherPart otherPart = dto.getOtherPart();
		
		otherPart.setUuid(StringUtils.trimToEmpty(metadata.getUuid()));
		otherPart.setMetadataLastModificationDate(StringUtils.trimToEmpty(metadata.getMetadataDate()));
		otherPart.setCharset(metadata.getResourceEncodingCharset());
		otherPart.setResourceLanguages(metadata.getResourceLanguages());
		otherPart.setMetadataLanguage(metadata.getMetadataLanguage());

		Format resourceFormat = metadata.getResourceFormat();
		if (resourceFormat != null)
		{
			FormatDTO formatDTO = new FormatDTO();
			if (resourceFormat.getName() != null)
			{
				formatDTO.setName(resourceFormat.getName().toString());
				if (resourceFormat.getVersion() != null)
				{
					formatDTO.setStringVersions(resourceFormat.getVersion().toString());
				}
			}
			otherPart.setFormat(formatDTO);
		}
		
		 if (dto instanceof ExperimentalSiteDTO)
		 {
			 MetadataSummaryDTO parentSummary = new MetadataSummaryDTO();
			 parentSummary.setUuid(metadata.getParentIdentifier());
			 ((ExperimentalSiteDTO) dto).setParentSummary(parentSummary);
		 }
		 
		 if (dto instanceof DatasetDTO)
		 {
			 ((DatasetDTO) dto).getMeasurementPart().setResourceGenealogy(toI18nString(metadata.getResourceGenealogy(metadataLocale, alternateLocales)));
			 if (StringUtils.isEmpty(metadata.getParentIdentifier())==false)
			 {
				 MetadataSummaryDTO experimentalSiteSummary = new MetadataSummaryDTO();
				 experimentalSiteSummary.setUuid(metadata.getParentIdentifier());
				 ((DatasetDTO) dto).setExperimentalSiteSummary(experimentalSiteSummary);
			 }
			 else
			 {
				 //Old hierachical mecanism
				 MetadataSummaryDTO experimentalSiteSummary = new MetadataSummaryDTO();
				 experimentalSiteSummary.setName(metadata.getDustbin().get(SedooMetadata.EXPERIMENTAL_SITE));
				 MetadataSummaryDTO observatorySummary = new MetadataSummaryDTO();
				 observatorySummary.setName(metadata.getDustbin().get(SedooMetadata.OBSERVATORY));
				 ((DatasetDTO) dto).setExperimentalSiteSummary(experimentalSiteSummary);
				 ((DatasetDTO) dto).setObservatorySummary(observatorySummary);
			 }
		 }

		
		return dto;
	}

	private static I18nString toI18nString(Map<Locale, String> values) 
	{
		I18nString result = new I18nString();
		result.setDefaultValue(values.get(null));
		HashMap<String, String> aux = new HashMap<String, String>();
		Iterator<Locale> iterator = values.keySet().iterator();
		while (iterator.hasNext()) {
			Locale locale = iterator.next();
			if (locale != null)
			{
				aux.put(Iso6392LanguageConverter.convertLocaleToIso6392(locale.getLanguage()) , values.get(locale));
			}
		}
		result.setI18nValues(aux);
		return result;
	}

	private static List<IdentifiedResourceIdentifier> toIdentifierResourceIdentifiers(List<ResourceIdentifier> resourceIdentifiers) 
	{
		List<IdentifiedResourceIdentifier> result = new ArrayList<IdentifiedResourceIdentifier>();
		Iterator<ResourceIdentifier> iterator = resourceIdentifiers.iterator();
		while (iterator.hasNext()) 
		{
			ResourceIdentifier resourceIdentifier = (ResourceIdentifier) iterator.next();
			result.add(new IdentifiedResourceIdentifier(resourceIdentifier.getCode(), resourceIdentifier.getNameSpace()));
		}
		return result;
	}
	
	private static List<InternetLink> toInternetLinks(List<ResourceLink> resourceLinks) 
	{
		List<InternetLink> result = new ArrayList<InternetLink>();
		Iterator<ResourceLink> iterator = resourceLinks.iterator();
		Long index = 1L;
		while (iterator.hasNext()) 
		{
			ResourceLink current = (ResourceLink) iterator.next();
			result.add(new InternetLink(index, current.getLink(), current.getLabel(), current.getProtocol()));
			index++;
		}
		return result;
	}

//	public static List<String> toStringList(List<IdentifiedString> src)
//	{
//		List<String> result = new ArrayList<String>();
////		Iterator<IdentifiedString> iterator = src.iterator();
////		while (iterator.hasNext())
////		{
////			result.add(iterator.next().getValue());
////		}
//		return result;
//	}

}
